﻿// <copyright file="AppData.cs" company="Microsoft Corporation">
// Copyright (c) 2009 Microsoft Corporation All Rights Reserved
// </copyright>
// <author>Michael S. Scherotter</author>
// <email>mischero@microsoft.com</email>
// <date>2009-05-28</date>
// <summary>Application Data</summary>

namespace MyOpenSpace
{
    using System.ComponentModel;
    using System.Globalization;
    using System.Windows.Browser;
    using opensocial;
    using Synergist;    
    
    /// <summary>
    /// User Application data
    /// </summary>
    /// <remarks>Uses the <a target="_blank" 
    /// href="http://wiki.opensocial.org/index.php?title=The_Persistence_API">
    /// OpenSocial Persistance API</a></remarks>
    public class AppData : INotifyPropertyChanged
    {
        #region Fields
        /// <summary>
        /// the app value stored
        /// </summary>
        private string appValue;

        /// <summary>
        /// the key to the app value
        /// </summary>
        private string key;

        /// <summary>
        /// the ID of the user (default is "opensocial.IdSpec.PersonId.VIEWER")
        /// </summary>
        private string id;

        /// <summary>
        /// the opensocial object
        /// </summary>
        private ScriptObject opensocial;
        #endregion

        #region Constructors
        /// <summary>
        /// Initializes a new instance of the AppData class.
        /// </summary>
        public AppData()
        {
            this.id = "opensocial.IdSpec.PersonId.VIEWER";
        }
        #endregion

        #region INotifyPropertyChanged Members

        /// <summary>
        /// Property changed event handler
        /// </summary>
        public event PropertyChangedEventHandler PropertyChanged;

        #endregion

        #region Properties
        /// <summary>
        /// Gets the opensocial object
        /// </summary>
        public ScriptObject OpenSocial
        {
            get
            {
                if (this.opensocial == null)
                {
                    try
                    {
                        this.opensocial = HtmlPage.Window.Eval("opensocial") as ScriptObject;
                    }
                    catch (System.InvalidOperationException ioe)
                    {
                        System.Diagnostics.Debug.WriteLine("Not running in an OpenSocial container: {0}", ioe.Message);

                        return null;
                    }
                }

                return this.opensocial;
            }
        }

        /// <summary>
        /// Gets or sets the user to read/write persistent data for
        /// </summary>
        public string Id
        {
            get
            {
                return this.id;
            }

            set
            {
                if (this.id != value)
                {
                    this.id = value;
                }
            }
        }

        /// <summary>
        /// Gets or sets the app data key
        /// </summary>
        public string Key
        {
            get
            {
                return this.key;
            }

            set
            {
                if (this.key != value)
                {
                    this.key = value;

                    this.SetValue();
                }
            }
        }

        /// <summary>
        /// Gets or sets the app data value
        /// </summary>
        public string Value
        {
            get
            {
                if (string.IsNullOrEmpty(this.appValue))
                {
                    this.FetchValue();
                }

                return this.appValue;
            }

            set
            {
                if (this.appValue != value)
                {
                    this.appValue = value;

                    this.SetValue();
                }
            }
        }
        #endregion

        #region Methods

        /// <summary>
        /// remove the key value
        /// </summary>
        public void RemoveValue()
        {
            if (this.OpenSocial == null)
            {
                return;
            }

            var dataRequest = new DataRequest(this.OpenSocial.Invoke("newDataRequest", null) as ScriptObject);

            var request = dataRequest.newRemovePersonAppDataRequest(this.Id, this.Key);

            dataRequest.add(request, this.Id.Eval());

            dataRequest.send(new opensocial.DataReceived(this.OnDataRemoved));
        }

        #endregion

        #region Implementation

        /// <summary>
        /// Fetch the value from persistent storage
        /// </summary>
        private void FetchValue()
        {
            if (this.OpenSocial == null)
            {
                return;
            }

            var dataRequest = new DataRequest(this.OpenSocial.Invoke("newDataRequest", null) as ScriptObject);

            var idSpec = new IdSpec()
            {
                UserId = this.Id.Eval()
            };

            var request = dataRequest.newFetchPersonAppDataRequest(idSpec, this.Key, null);

            dataRequest.add(request, "get_data");

            dataRequest.send(new opensocial.DataReceived(this.OnDataRetrieved));
        }

        /// <summary>
        /// Set the value to persistent storage
        /// </summary>
        private void SetValue()
        {
            if (string.IsNullOrEmpty(this.Key) || string.IsNullOrEmpty(this.Value))
            {
                return;
            }

            if (this.OpenSocial == null)
            {
                return;
            }

            var dataRequest = new DataRequest(this.OpenSocial.Invoke("newDataRequest", null) as ScriptObject);

            string jsonValue = "{" + string.Format(
                CultureInfo.InvariantCulture, 
                "\"{0}\" : \"{1}\"", 
                this.Key, 
                this.Value) + "}";

            var request = dataRequest.newUpdatePersonAppDataRequest(this.Id, this.Key, jsonValue);

            dataRequest.add(request, "set_data");

            dataRequest.send(new opensocial.DataReceived(this.OnDataUpdated));
        }

        /// <summary>
        /// Data updated event handler
        /// </summary>
        /// <param name="response">the data response</param>
        private void OnDataUpdated(DataResponse response)
        {
            if (response.HadError)
            {
            }
            else
            {
                var data = response.get("set_data").getData();
            }
        }
        
        /// <summary>
        /// Data retrieved event handler
        /// </summary>
        /// <param name="response">the data response</param>
        private void OnDataRetrieved(DataResponse response)
        {
            if (response.HadError)
            {
            }
            else
            {
                var data = response.get("get_data").getData();

                var viewerId = HtmlPage.Window.Eval("gadgets.views.getParams().viewerId") as string;

                var viewerData = data.GetProperty(viewerId) as ScriptObject;

                if (viewerData != null)
                {
                    var property = viewerData.GetProperty(this.Key) as ScriptObject;

                    if (property != null)
                    {
                        this.appValue = property.GetProperty(this.Key) as string;

                        if (this.PropertyChanged != null)
                        {
                            this.PropertyChanged(this, new PropertyChangedEventArgs("Value"));
                        }
                    }
                }
            }
        }

        /// <summary>
        /// Data removed event handler
        /// </summary>
        /// <param name="response">the data response</param>
        private void OnDataRemoved(DataResponse response)
        {
        }

        #endregion
    }
}
